home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / ingres04.lzh / source / support / ingres.y < prev    next >
Encoding:
Lex Description  |  1993-01-20  |  33.0 KB  |  1,614 lines

  1. %{
  2.  
  3. # include    <stdio.h>
  4. # include    <ctype.h>
  5. # include    <ingres.h>
  6. # include    <aux.h>
  7. # include    <version.h>
  8. # include    <access.h>
  9. # include    <lock.h>
  10. # include    <opsys.h>
  11. # include    <ctlmod.h>
  12. # include    <errno.h>
  13.  
  14. #ifdef sun
  15. extern int sys_nerr;
  16. extern char *sys_errlist[];
  17. #endif
  18.  
  19. /*
  20. **  INGRES -- INGRES startup
  21. **
  22. **    This program starts up the entire system.
  23. **
  24. **    Parameters:
  25. **        1 -- database name
  26. **        2 -- optional process table name
  27. **        x -- flags of the form +x or -x may be freely inter-
  28. **            sperced in the argument list.
  29. **
  30. **    Return:
  31. **        none if successful
  32. **        1 -- user error (no database, etc)
  33. **        -1 -- system error
  34. **
  35. **    Flags:
  36. **        -&xxxx -- EQUEL flag: xxxx are file descriptors for the
  37. **            status return pipe, the command write pipe, the
  38. **            data return pipe, and the data transfer pipe
  39. **            respectively.
  40. **        -@xxxx -- xxxx is same as EQUEL flag, but no flags
  41. **            are set.
  42. **        -*?? -- Masterid flag. Gives the siteid of the master
  43. **            site in a distributed ingres. (Used in dist.
  44. **            ingres' initproc() function.)
  45. **        -|xxxx -- Network flag.  This flag is just passed to
  46. **            the other processes, to be processed by the
  47. **            DBU's.
  48. **        -uusername -- set effective user to be username.  You
  49. **            must be INGRES or the DBA for the database to
  50. **            use this option.
  51. **        -cN -- set minimum character field output width to be
  52. **            N, default 6.  This is the fewest number of
  53. **            characters which may be output in any "c" type
  54. **            field.
  55. **        -inN -- integer output width.  this is the width of
  56. **            an integer field.  The small "n" is the size
  57. **            of the internal field ("1", "2", or "4") and
  58. **            N is the width of the field for that flag.
  59. **            The defaults are -i16, -i26, and -i413.
  60. **        -fnxN.M -- floating point output width and precision.
  61. **            Small "n" is the internal width in bytes ("4"
  62. **            or "8"), x is the format (f, F, g, G, e, E,
  63. **            n, or N), N is the field width, and M is the
  64. **            precision (number of digits after the decimal
  65. **            point).  The formats are:
  66. **            "f" or "F": FORTRAN-style F format: digits,
  67. **                decimal point, digits, no exponent.
  68. **            "e" or "E": FORTRAN-style E format: digits,
  69. **                decimal point, digits, letter "e" (or
  70. **                "E", depending on "x" in the param-
  71. **                eter), and an exponent.  The scaling
  72. **                factor is always one, that is, there
  73. **                is always one digit before the decimal
  74. **                point.
  75. **            "g" or "G": F format if it will fit in the
  76. **                field, otherwise E format.  Space is
  77. **                always left at the right of the field
  78. **                for the exponent, so that decimal
  79. **                points will align.
  80. **            "n" or "N": like G, except that space is not
  81. **                left for the decimal point in F style
  82. **                format (useful if you expect everything
  83. **                to fit, but you're not sure).
  84. **            The default is -fn10.3.
  85. **        -vx -- set vertical seperator for print operations
  86. **            and retrieves to the terminal to be "x".  The
  87. **            default is vertical bar ("|").
  88. **        +w -- database wait state.  If set ("+w"), you will
  89. **            wait until the database is not busy.  If clear,
  90. **            you will be informed if the database is busy.
  91. **            If not specified, the same operations take
  92. **            place depending on whether or not you are
  93. **            running in background (determined by whether
  94. **            or not your input is a teletype).  If in fore-
  95. **            ground, you are informed; if in background,
  96. **            you wait.
  97. **        -M -- monitor trace flag
  98. **        -P -- parser trace flag
  99. **        -O -- ovqp trace flag
  100. **        -Q -- qrymod trace flag
  101. **        -D -- decomp trace flag
  102. **        -Z -- dbu trace flag.  These flags require the 020 bit
  103. **            in the status field of the users file to be
  104. **            set.  The syntax is loose and is described
  105. **            elsewhere.  Briefly, "-Z" sets all flags except
  106. **            the last 20, "-Z4" sets flag 4, and "-Z5/7"
  107. **            sets all flags from 5 through 7.
  108. **        +L -- enable/disable upper to lower case mapping in the
  109. **            parser.  Used for debugging.
  110. **        -rmode -- retrieve into mode
  111. **        -nmode -- index mode.  These flags give the default
  112. **            modify mode for retrieve into and index.  They
  113. **            default to cheapsort and isam.  "Mode" can be
  114. **            any mode to modify except "truncated".
  115. **        +a -- enable/disable autoclear function in monitor.
  116. **            Default on.
  117. **        +b -- enable/disable batch update.  Default on.
  118. **            The 02 bit is needed to clear this flag.
  119. **        +d -- enable/disable printing of the dayfile.  Default
  120. **            on.
  121. **        +s -- enable/disable printing of almost everything from
  122. **            the monitor.
  123. **        +U -- enable/disable direct update of system catalogs.
  124. **            Default off.  The 04 bit is needed to set this
  125. **            option.
  126. **
  127. **    Files:
  128. **        .../files/usage -- to print a "usage: ..." message.
  129. **        .../data/base/<database>/admin -- to determine
  130. **            existance and some info about <database>.
  131. **        .../files/dayfile<VERSION> -- dayfile (printed by
  132. **            monitor).
  133. **        .../files/users -- file with UNIX uid -> INGRES code
  134. **            mapping, plus a pile of other information about
  135. **            the user.
  136. **        .../files/proctab<VERSION> -- default process table
  137. **
  138. **
  139. **    Note:
  140. **        this is also the startup program for sysmod.
  141. **        different flags are expected and the default process table
  142. **        is different from that of ingres.
  143. **
  144. */
  145.  
  146. # define    MAXOPTNS    10        /* maximum number of options you can specify */
  147. # define    SYSMAXOPTNS    6        /* maximum number of options to sysmod */
  148. # define    MAXPROCS    10        /* maximum number of processes in the system */
  149. # define    EQUELFLAG    '&'
  150. # define    NETFLAG        '|'        /* network slave flag */
  151. # define    CLOSED        '?'
  152.  
  153. char        Fileset[10];
  154. char        *Database;
  155. extern char    *Dbpath;        /* defined in initucode */
  156. extern int    Status;
  157. struct admin    Admin;            /* set in initucode */
  158. struct lockreq    Lock;
  159. FILE        *ProcFile;        /* fildes for the process table */
  160. char        *DefProcTab = NULL;    /* default process table name */
  161. char        *Opt[MAXOPTNS + 1];
  162. int        Nopts;
  163. int        No_exec;        /* if set, don't execute */
  164. int        NumProcs;        /* number of processes this system */
  165.  
  166.  
  167. /*
  168. **  Internal form of process descriptions.
  169. */
  170.  
  171. struct proc
  172. {
  173.     short        prstat;        /* status bits, see below */
  174.     char        prmpipe;    /* initial pipe to this process */
  175.     char        prtflag;    /* trace flag for CM this proc */
  176.     char        prpath[50];    /* pathname of this process */
  177.     struct _cm_t    prcm;        /* cm info passed to this proc */
  178. };
  179.  
  180. /* bits for prstat */
  181. # define PR_REALUID    0001        /* run as the user, not INGRES */
  182. # define PR_NOCHDIR    0002        /* don't chdir into database */
  183. # define PR_CLSSIN    0004        /* close standard input */
  184. # define PR_CLSDOUT    0010        /* close diagnostic output */
  185.  
  186. struct proc    ProcTab[CM_MAXPROC];
  187.  
  188.  
  189. /*
  190. **  Open pipe info.
  191. */
  192.  
  193. struct pipeinfo
  194. {
  195.     char    pip_rfd;    /* read file descriptor */
  196.     char    pip_wfd;    /* write file descriptor */
  197.     short    pip_rcnt;    /* read reference count */
  198.     short    pip_wcnt;    /* write reference count */
  199. };
  200.  
  201. struct pipeinfo Pipe[128];
  202.  
  203.  
  204. /*
  205. **  Macro definitions
  206. */
  207.  
  208. char    Macro[26][80];
  209.  
  210.  
  211. /* globals used by the grammar. */
  212. struct proc    *Proc;
  213. state_t        *StateP;
  214. proc_t        *ProcP;
  215. int        ProcNo;
  216. int        RemStat;
  217.  
  218.  
  219. %}
  220.  
  221. %union
  222. {
  223.     int    yyint;        /* integer */
  224.     char    *yystr;        /* string */
  225.     char    yypip;        /* pipe id */
  226.     char    yychar;        /* single character */
  227. }
  228.  
  229. %token    <yyint>    INT
  230. %token    <yystr>    STR
  231.  
  232. %type    <yyint>    procno stateno funcno
  233. %type    <yyint>    flags
  234. %type    <yystr>    pathname printname
  235. %type    <yypip>    pipe_id
  236. %type    <yychar>macro_id tflag
  237.  
  238. %%
  239.  
  240. proctab:    spec_list
  241.     ;
  242.  
  243. spec_list:    spec
  244.     |    spec_list spec
  245.     ;
  246.  
  247. spec:        proc_line states
  248.     |    macro_defn
  249.     ;
  250.  
  251. /*
  252. **  Lines beginning with "P" introduce new processes.
  253. **
  254. **    procno is the number of the process being defined.
  255. **    pathname is the pathname of the executable object
  256. **        of this module.
  257. **    printname is the name to be used as "Procname" in
  258. **        this module for activities unconnected with
  259. **        particular modules.
  260. **    pipe_id is the pipe to use as the normal input for
  261. **        this process.  It must be listed as a pipe
  262. **        in at least one of the constituent state
  263. **        definitions.
  264. **    flags are flags associated with this process.  They
  265. **        are not actually passed to the process, but
  266. **        are used internally.  See the #defines after
  267. **        /^struct proc/.
  268. */
  269.  
  270. proc_line:    'P' procno pathname printname pipe_id flags tflag
  271.         {
  272.             NumProcs++;
  273.             Proc = &ProcTab[$2];
  274.             smove($3, Proc->prpath);
  275.             Proc->prmpipe = Proc->prcm.cm_input = Proc->prcm.cm_rinput
  276.                 = Proc->prcm.cm_proc[$2].pr_ninput = $5;
  277.             smove($4, Proc->prcm.cm_myname);
  278.             Proc->prcm.cm_myproc = $2;
  279.             Proc->prstat = $6;
  280.             Proc->prtflag = $7;
  281.             Pipe[$5].pip_rcnt += 3;
  282.             Pipe[$5].pip_wcnt++;
  283.         }
  284.     ;
  285.  
  286. states:        state_line
  287.     |    states state_line
  288.     ;
  289.  
  290. state_line:    local_line
  291.     |    remote_line
  292.     ;
  293.  
  294. local_line:    'L' stateno flags funcno stateno
  295.         {
  296.             StateP = &Proc->prcm.cm_state[$2];
  297.             StateP->st_type = ST_LOCAL;
  298.             StateP->st_stat = $3;
  299.             StateP->st_v.st_loc.st_funcno = $4;
  300.             StateP->st_v.st_loc.st_next = $5;
  301.         }
  302.     ;
  303.  
  304. remote_line:    remote_header stateno_list
  305.     ;
  306.  
  307. remote_header:    'R' procno flags pipe_id pipe_id flags
  308.         {
  309.             ProcNo = $2;
  310.             ProcP = &Proc->prcm.cm_proc[ProcNo];
  311.             RemStat = $3;
  312.             ProcP->pr_file = $4;
  313.             ProcP->pr_ninput = $5;
  314.             ProcP->pr_stat = $6;
  315.             Pipe[$4].pip_wcnt++;
  316.             Pipe[$5].pip_rcnt++;
  317.         }
  318.     ;
  319.  
  320. stateno_list:        /* empty */
  321.     |    stateno_list remote_stateno
  322.     ;
  323.  
  324. remote_stateno:    stateno
  325.         {
  326.             StateP = &Proc->prcm.cm_state[$1];
  327.             StateP->st_type = ST_REMOT;
  328.             StateP->st_stat = RemStat;
  329.             StateP->st_v.st_rem.st_proc = ProcNo;
  330.         }
  331.     ;
  332.  
  333. /*
  334. **  Macro definitions.
  335. */
  336.  
  337. macro_defn:    'D' macro_id STR
  338.         {
  339.             smove($3, Macro[$2 - 'A']);
  340.         }
  341.  
  342. /*
  343. **  Productions for things that perhaps ought to be in the scanner.
  344. */
  345.  
  346. procno:        INT
  347.         {
  348.             if ($1 < 0 || $1 >= CM_MAXPROC)
  349.             {
  350.                 usrerr("Illegal proc number %d", $1);
  351.                 YYERROR;
  352.             }
  353.         }
  354.     ;
  355.  
  356. stateno:    INT
  357.         {
  358.             if ($1 < 0 || $1 >= CM_MAXST)
  359.             {
  360.                 usrerr("Illegal state number %d", $1);
  361.                 YYERROR;
  362.             }
  363.         }
  364.     ;
  365.  
  366. funcno:        INT
  367.         {
  368.             if ($1 < 0)
  369.             {
  370.                 usrerr("Illegal funcno %d", $1);
  371.                 YYERROR;
  372.             }
  373.         }
  374.     ;
  375.  
  376. pathname:    STR
  377.     ;
  378.  
  379. printname:    STR
  380.     ;
  381.  
  382. pipe_id:    STR
  383.         {
  384.             if ((islower($1[0]) || $1[0] == CLOSED) && $1[1] == '\0')
  385.                 $$ = $1[0];
  386.             else if ($1[0] == '|' && isdigit($1[1]) && $1[2] == '\0')
  387.                 $$ = $1[1];
  388.             else
  389.             {
  390.                 usrerr("Invalid pipe id \"%s\"", $1);
  391.                 YYERROR;
  392.             }
  393.         }
  394.     ;
  395.  
  396. tflag:        STR
  397.         {
  398.             if ($1[1] != '\0')
  399.             {
  400.                 usrerr("Invalid trace flag \"%s\"", $1);
  401.                 YYERROR;
  402.             }
  403.             else
  404.                 $$ = $1[0];
  405.         }
  406.     ;
  407.  
  408. flags:        INT
  409.     ;
  410.  
  411. macro_id:    STR
  412.         {
  413.             if ($1[0] < 'A' || $1[0] > 'Z' || $1[1] != '\0')
  414.             {
  415.                 usrerr("Invalid macro name \"%s\"", $1);
  416.                 YYERROR;
  417.             }
  418.             else
  419.                 $$ = $1[0];
  420.         }
  421.  
  422. %%
  423.  
  424. main(argc, argv)
  425. int    argc;
  426. char    **argv;
  427. {
  428.     register int    i;
  429.     register int    j;
  430.     extern char    *Proc_name;
  431.     int        fd;
  432.     char        *proctab;
  433.     register char    *p;
  434.     char        *ptr;
  435.     extern char    *Flagvect[];    /* defined in initucode.c */
  436.     extern char    *Parmvect[];    /* ditto */
  437.     char        *uservect[4];
  438.     char        buf[MAXLINE+1];
  439.     char        str[MAXLINE+1];    /* a string to put the Alockdes value into */
  440.     char        str2[MAXLINE+1];
  441.     extern    int    Wait_action;    /* action on lock driver */
  442.     int        CallSysmod = FALSE;
  443.     struct proc    *pr;
  444.     int        len;
  445.     char        *sysptr;
  446.  
  447.     /*
  448.     ** sysmod is linked to ingres.
  449.     ** check whether ingres or sysmod was called.
  450.     */
  451.     len =  strlen(argv[0]);
  452.     sysptr = &argv[0][len - 6];
  453.     if (sequal( sysptr, "sysmod"))
  454.     {
  455.         CallSysmod = TRUE;
  456.         Proc_name = "SYSMOD";
  457.     }
  458.     else
  459.         Proc_name = "INGRES";
  460.  
  461.  
  462.     itoa(getpid(), Fileset);
  463.     proctab = NULL;
  464.     Database = NULL;
  465.  
  466.     /*
  467.     **  Initialize everything, like Flagvect, Parmvect, Usercode,
  468.     **    etc.
  469.     */
  470.  
  471.     for (i = 0; i < 128; i++)
  472.         Pipe[i].pip_rfd = Pipe[i].pip_wfd = -1;
  473.  
  474.     i = initucode(argc, argv, TRUE, uservect, CallSysmod?M_EXCL:-1);
  475.     switch (i)
  476.     {
  477.       case 0:    /* ok */
  478.       case INDIRECT:
  479.         break;
  480.  
  481.       case NODB:    /* database does not exist */
  482.       case INDNODB:
  483.         printf("Database %s does not exist\n", Parmvect[0]);
  484.         if (CallSysmod)
  485.             goto sysusage;
  486.         else
  487.             goto usage;
  488.  
  489.       case NOACCESS:    /* you are not authorized */
  490.         printf("You may not access database %s\n", Database);
  491.         if (CallSysmod)
  492.             goto sysusage;
  493.         else
  494.             goto usage;
  495.  
  496.       case INVALIDUSR:    /* not a valid user */
  497.         printf("You are not a valid INGRES user\n");
  498.         if (CallSysmod)
  499.             goto sysusage;
  500.         else
  501.             goto usage;
  502.  
  503.       case NODBNAME:    /* no database name specified */
  504.         printf("No database name specified\n");
  505.         if (CallSysmod)
  506.             goto sysusage;
  507.         else
  508.             goto usage;
  509.  
  510.       default:
  511.         syserr("initucode %d", i);
  512.     }
  513.  
  514.     /*
  515.     **  Extract database name and process table name from
  516.     **    parameter vector.
  517.     **  Initialize the $P macro.
  518.     */
  519.  
  520.     Database = Parmvect[0];
  521.     proctab = Parmvect[1];
  522.     smove(Pathname, Macro['P' - 'A']);
  523.  
  524.     if (!CallSysmod)
  525.     {
  526.         /* scan flags in users file */
  527.         for (p = uservect[0]; *p != '\0'; p++)
  528.         {
  529.             /* skip initial blanks and tabs */
  530.             if (*p == ' ' || *p == '\t')
  531.                 continue;
  532.             ptr = p;
  533.  
  534.             /* find end of flag and null-terminate it */
  535.             while (*p != '\0' && *p != ' ' && *p != '\t')
  536.             p++;
  537.             i = *p;
  538.             *p = '\0';
  539.  
  540.             /* process the flag */
  541.             doflag(ptr, 1);
  542.             if (i == '\0')
  543.                 break;
  544.         }
  545.  
  546.         /* scan flags on command line */
  547.         for (i = 0; (p = Flagvect[i]) != NULL; i++)
  548.             doflag(p, 0);
  549.  
  550.         /* check for query modification specified for this database */
  551.         if ((Admin.adhdr.adflags & A_QRYMOD) == 0)
  552.             doflag("-q", -1);
  553.     }
  554.     /* special routine for handling sysmod flags */
  555.     else        
  556.     {
  557.         DefProcTab = "=sysmod";
  558.         if ( Flagvect[0] == NULL)
  559.         {
  560.             if (!bequal(Usercode, Admin.adhdr.adowner, UCODE_SZ))
  561.             {
  562.                 printf("You are not the dba for %s\n", Database);
  563.                 No_exec++;
  564.             }
  565.         }
  566.         for (i = 0; (p = Flagvect[i]) != NULL; i++)
  567.             sysflag(p);
  568.     }
  569.  
  570.  
  571.     /* close any extraneous files, being careful not to close anything we need */
  572.     for (i = 3; i < NOFILE; i++)
  573.     {
  574.         for (j = '0'; j <= '9'; j++)
  575.         {
  576.             if (Pipe[j].pip_wfd == i || Pipe[j].pip_rfd == i)
  577.                 break;
  578.         }
  579.         if (j > '9')
  580.             close(i);
  581.     }
  582.  
  583.     /* determine process table */
  584.     if (proctab == NULL)
  585.     {
  586.         /* use default proctab */
  587.         if (DefProcTab == NULL)
  588.         {
  589.             if (argv[0][length(argv[0]) - 1] == 'x')
  590.                 DefProcTab = "=procx";
  591.             else
  592.                 DefProcTab = "=proctab";
  593.             proctab = uservect[1];
  594.         }
  595.         if (proctab == NULL || proctab[0] == 0)
  596.         {
  597.             /* no proctab in users file */
  598.             concat(DefProcTab, VERSION, buf);
  599.             proctab = buf;
  600.         }
  601.     }
  602.     else
  603.     {
  604.         /* proctab specified; check permissions */
  605.         if ((Status & (proctab[0] == '=' ? U_EPROCTAB : U_APROCTAB)) == 0)
  606.         {
  607.             printf("You may not specify this process table\n");
  608.             if (CallSysmod)
  609.                 goto sysusage;
  610.             else
  611.                 goto usage;
  612.         }
  613.     }
  614.  
  615.     /* expand process table name */
  616.     if (proctab[0] == '=')
  617.     {
  618.         smove(ztack(ztack(Pathname, "/files/"), &proctab[1]), buf);
  619.         proctab = buf;
  620.     }
  621.  
  622.     /* open and read the process table */
  623.     if ((ProcFile = fopen(proctab, "r")) == NULL)
  624.     {
  625.         printf("Proctab %s: %s\n", proctab, sys_errlist[errno]);
  626.         if (CallSysmod)
  627.             goto sysusage;
  628.         else
  629.             goto usage;
  630.     }
  631.  
  632.     /* build internal form of the process table */
  633.     if (yyparse())
  634.         No_exec++;
  635.  
  636.     /* don't bother executing if we have found errors */
  637.     if (No_exec)
  638.     {
  639.         if (!CallSysmod)
  640.         {
  641.           usage:
  642.             /* cat .../files/usage */
  643.             cat(ztack(Pathname, "/files/usage"));
  644.             exit(1);
  645.         }
  646.         else
  647.         {
  648.         sysusage:
  649.             cat(ztack(Pathname, "/files/sysusage"));
  650.             exit(1);
  651.         }
  652.     }
  653.  
  654.     fclose(ProcFile);
  655.  
  656. #ifdef NETLOCK 
  657.     /* set locks on the database */
  658.     if (!CallSysmod) {
  659.         dolocks();
  660.         if ( Alockdes >= 0 )
  661.         {
  662.             sprintf(str,"-l%d",(flagval('E') >0 ?M_EXCL : M_SHARE));
  663.             doflag(str,-1);
  664.             sprintf(str2,"-W%d",Wait_action);
  665.             doflag(str2,-1);
  666.             close(Alockdes);
  667.         }
  668.     }
  669. #endif
  670.  
  671.     /* satisfy process table (never returns) */
  672.         satisfypt(CallSysmod);
  673. }
  674.  
  675.  
  676.  
  677. /*
  678. **  Process rubouts (just exit)
  679. */
  680.  
  681. rubproc()
  682. {
  683.     exit(2);
  684. }
  685. /*
  686. **  DOFLAG -- process flag
  687. **
  688. **    Parameters:
  689. **        flag -- the flag (as a string)
  690. **        where -- where it is called from
  691. **            -1 -- internally inserted
  692. **            0 -- on user command line
  693. **            1 -- from users file
  694. **
  695. **    Return:
  696. **        none
  697. **
  698. **    Side effects:
  699. **        All flags are inserted on the end of the
  700. **        "Flaglist" vector for passing to the processes.
  701. **        The "No_exec" flag is set if the flag is bad or you
  702. **        are not authorized to use it.
  703. **
  704. **    Requires:
  705. **        Status -- to get the status bits set for this user.
  706. **        syserr -- for the obvious
  707. **        printf -- to print errors
  708. **        atoi -- to check syntax on numerically-valued flags
  709. **
  710. **    Defines:
  711. **        doflag()
  712. **        Flagok -- a list of legal flags and attributes (for
  713. **            local use only).
  714. **        Relmode -- a list of legal relation modes.
  715. **
  716. **    Called by:
  717. **        main
  718. **
  719. **    History:
  720. **        11/6/79 (6.2/8) (eric) -- -u flag processing dropped,
  721. **            since initucode does it anyhow.  -E flag
  722. **            removed (what is it?).  F_USER code dropped.
  723. **            F_DROP is still around; we may need it some-
  724. **            day.  Also, test of U_SUPER flag and/or DBA
  725. **            status was wrong.
  726. **        7/5/78 (eric) -- NETFLAG added to list.
  727. **        3/27/78 (eric) -- EQUELFLAG added to the list.
  728. **        1/29/78 -- do_u_flag broken off by eric
  729. **        1/4/78 -- written by eric
  730. */
  731.  
  732. struct flag
  733. {
  734.     char    flagname;    /* name of the flag */
  735.     char    flagstat;    /* status of flag (see below) */
  736.     int    flagsyntx;    /* syntax code for this flag */
  737.     int    flagperm;    /* status bits needed to use this flag */
  738.     char    *flagpt;    /* default proctab to use with this flag */
  739. };
  740.  
  741. /* status bits for flag */
  742. # define    F_PLOK        01    /* allow +x form */
  743. # define    F_PLD        02    /* defaults to +x */
  744. # define    F_DBA        04    /* must be the DBA to use */
  745. # define    F_DROP        010    /* don't save in Flaglist */
  746.  
  747. /* syntax codes */
  748. # define    F_ACCPT        1    /* always accept */
  749. # define    F_C_SPEC    3    /* -cN spec */
  750. # define    F_I_SPEC    4    /* -inN spec */
  751. # define    F_F_SPEC    5    /* -fnxN.M spec */
  752. # define    F_CHAR        6    /* single character */
  753. # define    F_MODE        7    /* a modify mode */
  754. # define    F_INTERNAL    8    /* internal flag, e.g., -q */
  755. # define    F_EQUEL        9    /* EQUEL flag */
  756.  
  757. struct flag    Flagok[] =
  758. {
  759.     'a',    F_PLD|F_PLOK,    F_ACCPT,    0,        NULL,
  760.     'b',    F_PLD|F_PLOK,    F_ACCPT,    U_DRCTUPDT,    NULL,
  761.     'c',    0,        F_C_SPEC,    0,        NULL,
  762.     'd',    F_PLD|F_PLOK,    F_ACCPT,    0,        NULL,
  763.     'f',    0,        F_F_SPEC,    0,        NULL,
  764.     'i',    0,        F_I_SPEC,    0,        NULL,
  765.     'l',    F_PLOK,        F_INTERNAL,    0,        NULL,
  766.     'n',    0,        F_MODE,        0,        NULL,
  767.     'q',    F_PLD|F_PLOK,    F_INTERNAL,    0,        NULL,
  768.     'r',    0,        F_MODE,        0,        NULL,
  769.     's',    F_PLD|F_PLOK,    F_ACCPT,    0,        NULL,
  770.     'v',    0,        F_CHAR,        0,        NULL,
  771.     'w',    F_PLOK|F_DROP,    F_ACCPT,    0,        NULL,
  772.     'D',    0,        F_ACCPT,    U_TRACE,    NULL,
  773.     'L',    F_PLOK,        F_ACCPT,    0,        NULL,
  774.     'M',    0,        F_ACCPT,    U_TRACE,    NULL,
  775.     'O',    0,        F_ACCPT,    U_TRACE,    NULL,
  776.     'P',    0,        F_ACCPT,    U_TRACE,    NULL,
  777.     'Q',    0,        F_ACCPT,    U_TRACE,    NULL,
  778.     'T',    0,        F_ACCPT,    U_TRACE,    NULL,
  779.     'U',    F_PLOK,        F_ACCPT,    U_UPSYSCAT,    NULL,
  780.     'W',    0,        F_INTERNAL,    0,        NULL,
  781.     'Z',    0,        F_ACCPT,    U_TRACE,    NULL,
  782.     EQUELFLAG, 0,        F_EQUEL,    0,        "=equel",
  783.     NETFLAG, 0,        F_EQUEL,    0,        "=slave",
  784.     '@',    0,        F_EQUEL,    0,        NULL,
  785.     '*',    0,        F_ACCPT,    0,        NULL,
  786.     0,    0,        0,        0,        NULL,
  787. };
  788.  
  789. /* list of valid retrieve into or index modes */
  790. char    *Relmode[] =
  791. {
  792.     "isam",
  793.     "cisam",
  794.     "hash",
  795.     "chash",
  796.     "heap",
  797.     "cheap",
  798.     "heapsort",
  799.     "cheapsort",
  800.     NULL
  801. };
  802.  
  803.  
  804. doflag(flag, where)
  805. char    *flag;
  806. int    where;
  807. {
  808.     register char        *p;
  809.     register struct flag    *f;
  810.     auto int        intxx;
  811.     register char        *ptr;
  812.     int            i;
  813.     int            j;
  814.  
  815.     p = flag;
  816.  
  817.     /* check for valid flag format (begin with + or -) */
  818.     if (p[0] != '+' && p[0] != '-')
  819.         goto badflag;
  820.  
  821.     /* check for flag in table */
  822.     for (f = Flagok; f->flagname != p[1]; f++)
  823.     {
  824.         if (f->flagname == 0)
  825.             goto badflag;
  826.     }
  827.  
  828.     /* check for +x form allowed */
  829.     if (p[0] == '+' && (f->flagstat & F_PLOK) == 0)
  830.         goto badflag;
  831.  
  832.     /* check for permission to use the flag */
  833.     if ((f->flagperm != 0 && (Status & f->flagperm) == 0 &&
  834.          (((f->flagstat & F_PLD) == 0) ? (p[0] == '+') : (p[0] == '-'))) ||
  835.         ((f->flagstat & F_DBA) != 0 && (Status & U_SUPER) == 0 &&
  836.          !bequal(Usercode, Admin.adhdr.adowner, UCODE_SZ)))
  837.     {
  838.         printf("You are not authorized to use the %s flag\n", p);
  839.         No_exec++;
  840.     }
  841.  
  842.     /* check syntax */
  843.     switch (f->flagsyntx)
  844.     {
  845.       case F_ACCPT:
  846.         break;
  847.  
  848.       case F_C_SPEC:
  849.         if ((intxx = atoi(&p[2])) > MAXFIELD)
  850.             goto badflag;
  851.         break;
  852.  
  853.       case F_I_SPEC:
  854.         if (p[2] != '1' && p[2] != '2' && p[2] != '4')
  855.             goto badflag;
  856.         if ((intxx = atoi(&p[3])) > MAXFIELD)
  857.             goto badflag;
  858.         break;
  859.  
  860.       case F_F_SPEC:
  861.         if (p[2] != '4' && p[2] != '8')
  862.             goto badflag;
  863.         switch (p[3])
  864.         {
  865.           case 'e':
  866.           case 'E':
  867.           case 'f':
  868.           case 'F':
  869.           case 'g':
  870.           case 'G':
  871.           case 'n':
  872.           case 'N':
  873.             break;
  874.  
  875.           default:
  876.             goto badflag;
  877.  
  878.         }
  879.         ptr = &p[4];
  880.         while (*ptr != '.')
  881.             if (*ptr == 0)
  882.                 goto badflag;
  883.             else
  884.                 ptr++;
  885.         *ptr = 0;
  886.         if ((intxx = atoi(&p[4])) > MAXFIELD)
  887.             goto badflag;
  888.         *ptr++ = '.';
  889.         if ((intxx = atoi(ptr)) > MAXFIELD)
  890.             goto badflag;
  891.         break;
  892.  
  893.       case F_CHAR:
  894.         if (p[2] == 0 || p[3] != 0)
  895.             goto badflag;
  896.         break;
  897.  
  898.       case F_MODE:
  899.         for (i = 0; (ptr = Relmode[i]) != NULL; i++)
  900.         {
  901.             if (sequal(&p[2], ptr))
  902.                 break;
  903.         }
  904.         if (ptr == NULL)
  905.             goto badflag;
  906.         break;
  907.  
  908.       case F_INTERNAL:
  909.         if (where >= 0)
  910.             goto badflag;
  911.         break;
  912.  
  913.       case F_EQUEL:
  914.         ptr = &p[2];
  915.         for (i = 0; i < 20; i++, ptr++)
  916.         {
  917.             if (*ptr == CLOSED)
  918.                 continue;
  919.             if (*ptr < 0100 || *ptr >= 0100 + NOFILE)
  920.                 break;
  921.             j = (i / 2) + '0';
  922.             if ((i & 01) == 0)
  923.             {
  924.                 Pipe[j].pip_rfd = *ptr & 077;
  925.             }
  926.             else
  927.             {
  928.                 Pipe[j].pip_wfd = *ptr & 077;
  929.             }
  930.         }
  931.         break;
  932.  
  933.       default:
  934.         syserr("doflag: syntx %d", f->flagsyntx);
  935.  
  936.     }
  937.  
  938.     /* save flag */
  939.     if (Nopts >= MAXOPTNS)
  940.     {
  941.         printf("Too many options to INGRES\n");
  942.         exit(1);
  943.     }
  944.     if ((f->flagstat & F_DROP) == 0)
  945.         Opt[Nopts++] = p;
  946.  
  947.     /* change to new process table as appropriate */
  948.     if (f->flagpt != NULL)
  949.         DefProcTab = f->flagpt;
  950.  
  951.     return;
  952.  
  953.   badflag:
  954.     printf("Bad flag format: %s\n", p);
  955.     No_exec++;
  956.     return;
  957. }
  958. /*
  959. **  DOLOCKS -- set database lock
  960. **
  961. **    A lock is set on the database.
  962. */
  963.  
  964. dolocks()
  965. {
  966.     db_lock(flagval('E') > 0 ? M_EXCL : M_SHARE);
  967. }
  968. /*
  969. **  FLAGVAL -- return value of flag
  970. **
  971. **    Parameter:
  972. **        flag -- the name of the flag
  973. **
  974. **    Return:
  975. **        -1 -- flag is de-asserted (-x)
  976. **        0 -- flag is not specified
  977. **        1 -- flag is asserted (+x)
  978. **
  979. **    Requires:
  980. **        Opt -- to scan the flags
  981. **
  982. **    Defines:
  983. **        flagval
  984. **
  985. **    Called by:
  986. **        buildint
  987. **        dolocks
  988. **
  989. **    History:
  990. **        3/27/78 (eric) -- changed to handle EQUEL flag
  991. **            normally.
  992. **        1/4/78 -- written by eric
  993. */
  994.  
  995. flagval(flag)
  996. char    flag;
  997. {
  998.     register char    f;
  999.     register char    **p;
  1000.     register char    *o;
  1001.  
  1002.     f = flag;
  1003.  
  1004.     /* start scanning option list */
  1005.     for (p = Opt; (o = *p) != 0; p++)
  1006.     {
  1007.         if (o[1] == f)
  1008.             if (o[0] == '+')
  1009.                 return (1);
  1010.             else
  1011.                 return (-1);
  1012.     }
  1013.     return (0);
  1014. }
  1015. /*
  1016. **  SATISFYPT -- satisfy the process table
  1017. **
  1018. **    Well folks, now that you've read this far, this is it!!!  I
  1019. **    mean, this one really does it!!!  It takes the internal form
  1020. **    built by the parser and creates pipes as necessary, forks, and
  1021. **    execs the INGRES processes.  Isn't that neat?
  1022. **
  1023. **    Parameters:
  1024. **        none
  1025. **
  1026. **    Returns:
  1027. **        never
  1028. **
  1029. **    Requires:
  1030. **        Proctab -- the internal form
  1031. **        ingexec -- to actually exec the process
  1032. **        pipe -- to create the pipe
  1033. **        syserr -- for the obvious
  1034. **        fillpipe -- to extend a newly opened pipe through all
  1035. **            further references to it.
  1036. **        checkpipes -- to see if a given pipe will ever be
  1037. **            referenced again.
  1038. **        fork -- to create a new process
  1039. **
  1040. **    Defines:
  1041. **        satisfypt
  1042. **
  1043. **    Called by:
  1044. **        main
  1045. **
  1046. **    History:
  1047. **        3/14/80 (eric) -- changed for version 7.0.
  1048. **        7/24/78 (eric) -- Actual file descriptors stored in
  1049. **            'prpipes' are changed to have the 0100 bit
  1050. **            set internally (as well as externally), so
  1051. **            fd 0 will work correctly.
  1052. **        1/4/78 -- written by eric
  1053. */
  1054.  
  1055.  
  1056.  
  1057. satisfypt(callsysmod)
  1058. int    callsysmod;
  1059. {
  1060.     register struct proc    *pr;
  1061.     register proc_t        *pp;
  1062.     register int        i;
  1063.     int            procno;
  1064.     register int        pip;
  1065.  
  1066.     /* scan the process table */
  1067.     for (procno = CM_MAXPROC - 1; procno >= 0; procno--)
  1068.     {
  1069.  
  1070.         pr = &ProcTab[procno];
  1071.         if (pr->prpath[0] == '\0')
  1072.             continue;
  1073.  
  1074.         /* scan pipe vector, creating new pipes as needed */
  1075.         pipeopen(pr->prmpipe, TRUE);
  1076.         pipeopen(pr->prcm.cm_input, FALSE);
  1077.         pipeopen(pr->prcm.cm_rinput, FALSE);
  1078.         for (i = 0; i < CM_MAXPROC; i++)
  1079.         {
  1080.             pp = &pr->prcm.cm_proc[i];
  1081.             pipeopen(pp->pr_file, TRUE);
  1082.             pipeopen(pp->pr_ninput, FALSE);
  1083.         }
  1084.  
  1085.         /* substitute real file descriptors throughout */
  1086.         pipexlat(&pr->prmpipe, TRUE);
  1087.         pipexlat(&pr->prcm.cm_input, FALSE);
  1088.         pipexlat(&pr->prcm.cm_rinput, FALSE);
  1089.         for (i = 0; i < CM_MAXPROC; i++)
  1090.         {
  1091.             pp = &pr->prcm.cm_proc[i];
  1092.             pipexlat(&pp->pr_file, TRUE);
  1093.             pipexlat(&pp->pr_ninput, FALSE);
  1094.         }
  1095.  
  1096.         /* fork if necessary */
  1097.         if (--NumProcs <= 0  || (i = fork()) == 0 )
  1098.         {
  1099.             /* child!! */
  1100.             ingexec(procno);
  1101.         }
  1102.  
  1103.         /* parent */
  1104.         if (i < 0)
  1105.             syserr("satisfypt: fork");
  1106.  
  1107.         /* scan pipes.  close all not used in the future */
  1108.         for (i = 0; i < 128; i++)
  1109.         {
  1110.             if (i == CLOSED)
  1111.                 continue;
  1112.             if (Pipe[i].pip_rcnt <= 0 && Pipe[i].pip_rfd >= 0)
  1113.             {
  1114.                 if (close(Pipe[i].pip_rfd) < 0)
  1115.                     syserr("satisfypt: close-r(%d)", Pipe[i].pip_rfd);
  1116.                 Pipe[i].pip_rfd = -1;
  1117.             }
  1118.             if (Pipe[i].pip_wcnt <= 0 && Pipe[i].pip_wfd >= 0)
  1119.             {
  1120.                 if (close(Pipe[i].pip_wfd) < 0)
  1121.                     syserr("satisfypt: close-w(%d)", Pipe[i].pip_wfd);
  1122.                 Pipe[i].pip_wfd = -1;
  1123.             }
  1124.         }
  1125.     }
  1126.     syserr("satisfypt: fell out");
  1127. }
  1128.  
  1129.  
  1130. /*
  1131. **  SYSFLAG -- process flags for sysmod
  1132. **
  1133. **    Parameters:
  1134. **        flag -- the flag (as a string)
  1135. **        may be one of: -s, -S, -T? 
  1136. **
  1137. **    Return:
  1138. **        none
  1139. **
  1140. **    Side effects:
  1141. **        All flags are inserted on the end of the
  1142. **        "Flaglist" vector for passing to the processes.
  1143. **        The "No_exec" flag is set if the flag is bad or you
  1144. **        are not authorized to use it.
  1145. **
  1146. **    Called by:
  1147. **        main
  1148. **
  1149. */
  1150.  
  1151. sysflag(flag)
  1152. char     *flag;
  1153. {
  1154.     register char     *p;
  1155.  
  1156.     p = flag;
  1157.  
  1158.     if (p[0] != '-')
  1159.         goto sysbadflag;
  1160.  
  1161.     switch (p[1])
  1162.     {
  1163.         case 's':
  1164.         if ((Status & U_SUPER) == 0)
  1165.         {
  1166.             printf("Only INGRES can use the -s flag\n");
  1167.             No_exec++;
  1168.             return;
  1169.         }
  1170.         bmove(Admin.adhdr.adowner, Usercode, UCODE_SZ);
  1171.         return(0);
  1172.         break;
  1173.  
  1174.         case 'R':
  1175.       case 'S':
  1176.         break;
  1177.     
  1178.       default:
  1179.         goto sysbadflag;
  1180.     }
  1181.  
  1182.     if (!bequal(Usercode, Admin.adhdr.adowner, UCODE_SZ))
  1183.     {
  1184.         printf("You are not the dba for %s\n", Database);
  1185.         No_exec++;
  1186.         return;
  1187.     }
  1188.  
  1189.  
  1190.     /* save flag */
  1191.     if (Nopts >= SYSMAXOPTNS)
  1192.     {
  1193.         printf("Too many options to SYSMOD\n");
  1194.         exit(1);
  1195.     }
  1196.  
  1197.     Opt[Nopts++] = p;
  1198.  
  1199.  
  1200.     return(0);
  1201.  
  1202.  
  1203.     sysbadflag:
  1204.     printf("Sysmod: bad flag format: %s \n", p);
  1205.     No_exec++;
  1206.     return;
  1207.  
  1208. }
  1209.  
  1210. /*
  1211. **  PIPEOPEN -- open pipe if necessary.
  1212. */
  1213.  
  1214. pipeopen(pipid, rw)
  1215.     char pipid;
  1216.     int rw;
  1217. {
  1218.     register struct pipeinfo *pi;
  1219.     int pipex[2];
  1220.  
  1221.     if (pipid == '\0')
  1222.         return;
  1223.  
  1224.     pi = &Pipe[pipid];
  1225.  
  1226.     if ((rw ? pi->pip_wfd : pi->pip_rfd) >= 0)
  1227.         return;
  1228.     if (pi->pip_rfd >= 0 || pi->pip_wfd >= 0)
  1229.         syserr("pipeopen %o %d: rfd=%d, wfd=%d", pipid, rw, pi->pip_rfd, pi->pip_wfd);
  1230.     if (pipid == CLOSED)
  1231.         pi->pip_rfd = pi->pip_wfd = CLOSED;
  1232.     else
  1233.     {
  1234.         if (pipe(pipex) < 0)
  1235.             syserr("pipeopen: pipe");
  1236.         pi->pip_rfd = pipex[0];
  1237.         pi->pip_wfd = pipex[1];
  1238.     }
  1239. }
  1240. /*
  1241. **  CHECKPIPES -- check for pipe referenced in the future
  1242. **
  1243. **    Parameters:
  1244. **        proc -- point in the process table to start looking
  1245. **            from.
  1246. **        fd -- the file descriptor to look for.
  1247. **
  1248. **    Return:
  1249. **        zero -- it will be referenced in the future.
  1250. **        one -- it is never again referenced.
  1251. **
  1252. **    Requires:
  1253. **        nothing
  1254. **
  1255. **    Defines:
  1256. **        checkpipes
  1257. **
  1258. **    Called by:
  1259. **        satisfypt
  1260. **
  1261. **    History:
  1262. **        7/24/78 (eric) -- 0100 bit on file descriptors handled.
  1263. **        1/4/78 -- written by eric
  1264. */
  1265.  
  1266. checkpipes(proc, fd)
  1267. struct proc    *proc;
  1268. register int    fd;
  1269. {
  1270.     register struct proc    *pr;
  1271.     register proc_t        *pp;
  1272.     register int        i;
  1273.  
  1274.     for (pr = proc; pr < &ProcTab[CM_MAXPROC]; pr++)
  1275.     {
  1276.         if (pr->prpath[0] == '\0')
  1277.             continue;
  1278.         for (i = 0; i < CM_MAXPROC; i++)
  1279.         {
  1280.             pp = &pr->prcm.cm_proc[i];
  1281.             if (pp->pr_file == fd || pp->pr_ninput == fd)
  1282.                 return (0);
  1283.         }
  1284.     }
  1285.     return (1);
  1286. }
  1287. /*
  1288. **  INGEXEC -- execute INGRES process
  1289. **
  1290. **    This routine handles all the setup of the argument vector
  1291. **    and then executes a process.
  1292. **
  1293. **    Parameters:
  1294. **        process -- a pointer to the process table entry which
  1295. **            describes this process.
  1296. **
  1297. **    Returns:
  1298. **        never
  1299. **
  1300. **    Side Effects:
  1301. **        never returns, but starts up a new overlay.  Notice
  1302. **            that it does NOT fork.
  1303. **
  1304. **    Requires:
  1305. **        none
  1306. **
  1307. **    Called By:
  1308. **        satisfypt
  1309. **
  1310. **    Trace Flags:
  1311. **        none
  1312. **
  1313. **    Diagnostics:
  1314. **        none
  1315. **
  1316. **    Syserrs:
  1317. **        chdir %s -- could not change directory into the data-
  1318. **            base.
  1319. **        creat %s -- could not create the redirected standard
  1320. **            output file.
  1321. **        %s not executable -- could not execute the process.
  1322. **
  1323. **    History:
  1324. **        8/9/78 (eric) -- changed "prparam" to be a colon-
  1325. **            separated list of parameters (so the number
  1326. **            is variable); also, moved parameter expansion
  1327. **            into this routine from buildint() so that
  1328. **            the colons in the dbu part of the proctab
  1329. **            would not confuse things.
  1330. **        7/24/78 (eric) -- changed the technique of closing
  1331. **            files 0 & 2 so that they will never be closed
  1332. **            (even if requested in the status field)
  1333. **            if they are mentioned in the pipe vector.
  1334. **            Also, some fiddling is done to handle the
  1335. **            0100 bit on file descriptors correctly.
  1336. */
  1337.  
  1338. ingexec(procno)
  1339.     int procno;
  1340. {
  1341.     char            *vect[30];
  1342.     register char        **v;
  1343.     char            **opt;
  1344.     int            i;
  1345.     register struct proc    *pr;
  1346.     register proc_t        *pp;
  1347.     register char        *p;
  1348.     int            outfd;
  1349.     char            closeit[NOFILE];
  1350.     char            fdbuf[3];
  1351.  
  1352.     v = vect;
  1353.     pr = &ProcTab[procno];
  1354.  
  1355.     *v++ = pr->prpath;
  1356.     fdbuf[0] = pr->prcm.cm_rinput | 0100;
  1357.     fdbuf[1] = pr->prtflag;
  1358.     fdbuf[2] = '\0';
  1359.     *v++ = fdbuf;
  1360.     *v++ = Fileset;
  1361.     *v++ = Usercode;
  1362.     *v++ = Database;
  1363.     *v++ = Pathname;
  1364.  
  1365.     /* insert flag parameters */
  1366.     for (opt = Opt; *opt; opt++)
  1367.         *v++ = *opt;
  1368.     *v = 0;
  1369.  
  1370.     /* set up 'closeit' to tell which pipes to close */
  1371.     for (i = 0; i < NOFILE; i++)
  1372.         closeit[i] = TRUE;
  1373.     closeit[pr->prmpipe & 077] = FALSE;
  1374.     closeit[pr->prcm.cm_input & 077] = FALSE;
  1375.     closeit[pr->prcm.cm_rinput & 077] = FALSE;
  1376.     for (i = 0; i < CM_MAXPROC; i++)
  1377.     {
  1378.         pp = &pr->prcm.cm_proc[i];
  1379.         if (pp->pr_ninput != CLOSED)
  1380.             closeit[pp->pr_ninput & 077] = FALSE;
  1381.         if (pp->pr_file != CLOSED)
  1382.             closeit[pp->pr_file & 077] = FALSE;
  1383.     }
  1384.     closeit[1] = FALSE;
  1385.     if ((pr->prstat & PR_CLSSIN) == 0)
  1386.         closeit[0] = FALSE;
  1387.     if ((pr->prstat & PR_CLSDOUT) == 0)
  1388.         closeit[2] = FALSE;
  1389.  
  1390.     /* close extra pipes (those not used by this process) */
  1391.     for (i = 0; i < NOFILE; i++)
  1392.     {
  1393.         if (closeit[i])
  1394.             close(i);
  1395.     }
  1396.  
  1397.     /* change to the correct directory */
  1398.     if ((pr->prstat & PR_NOCHDIR) == 0)
  1399.     {
  1400.         if (chdir(Dbpath))
  1401.             syserr("ingexec: chdir %s", Dbpath);
  1402.     }
  1403.  
  1404.     /* change to normal userid/groupid if a non-dangerous process */
  1405.     if ((pr->prstat & PR_REALUID) != 0)
  1406.     {
  1407.         setuid(getuid());
  1408. #        ifndef xB_UNIX
  1409.         setgid(getgid());
  1410. #        endif
  1411.     }
  1412.  
  1413. # ifdef LEAVEOUT
  1414.     /* change standard output if specified in proctab */
  1415.     p = pr->prstdout;
  1416.     if (*p != 0)
  1417.     {
  1418.         /* chew up fd 0 (just in case) */
  1419.         outfd = dup(1);
  1420.         close(1);
  1421.         if (creat(p, 0666) != 1)
  1422.         {
  1423.             /* restore standard output and print error */
  1424.             close(1);
  1425.             dup(outfd);    /* better go into slot 1 */
  1426.             syserr("ingexec: creat %s", p);
  1427.         }
  1428.         close(outfd);
  1429.     }
  1430. # endif LEAVEOUT
  1431.  
  1432.     /*
  1433.     **  PLEASE NOTE THE TRICKERY USED HERE.
  1434.     **    In this code I depend on UNIX buffering pipes at least
  1435.     **    enough to handle one "CM" struct.  If not, the following
  1436.     **    write will hang before the exec will call the process
  1437.     **    that will read it.
  1438.     **
  1439.     **    The "correct" way to do this is to fork & have the
  1440.     **    parent write the CM struct.  But how do I handle the
  1441.     **    last one (that does not fork)?  I could also do an
  1442.     **    extra fork of a process to do the write.  But some
  1443.     **    systems have a limit on processes, and besides, it
  1444.     **    seems like a lot of overhead for such a little thing.
  1445.     **
  1446.     **    Perhaps I should encode the CM struct into argv
  1447.     **    instead & do it "right".
  1448.     */
  1449.  
  1450.     /* output the control structure to the awaiting process... */
  1451.     write(pr->prmpipe & 077, &pr->prcm, sizeof pr->prcm);
  1452.     close(pr->prmpipe & 077);
  1453.  
  1454.     /* give it the old college (or in this case, University) try */
  1455.     execv(vect[0], vect);
  1456.     syserr("\"%s\" not executable", vect[0]);
  1457. }
  1458.  
  1459.  
  1460.  
  1461. pipexlat(ppip, rw)
  1462.     char *ppip;
  1463.     int rw;
  1464. {
  1465.     register struct pipeinfo *pi;
  1466.     int cnt;
  1467.     int fd;
  1468.  
  1469.     if (*ppip == '\0' || *ppip == CLOSED)
  1470.         return;
  1471.     pi = &Pipe[*ppip];
  1472.  
  1473.     if (rw)
  1474.     {
  1475.         cnt = --(pi->pip_wcnt);
  1476.         fd = pi->pip_wfd;
  1477.     }
  1478.     else
  1479.     {
  1480.         cnt = --(pi->pip_rcnt);
  1481.         fd = pi->pip_rfd;
  1482.     }
  1483.  
  1484.     if (cnt < 0)
  1485.         syserr("pipexlat: cnt=%d: %o %d", cnt, *ppip, rw);
  1486.     if (fd < 0 || fd > NOFILE)
  1487.         syserr("pipexlat: fd=%d: %o %d", fd, *ppip, rw);
  1488.  
  1489.     *ppip = fd;
  1490. }
  1491. /*
  1492. **  YYLEX -- Return next token from proctab
  1493. **
  1494. **    Parameters:
  1495. **        none
  1496. **
  1497. **    Returns:
  1498. **        Next token
  1499. **
  1500. **    Side Effects:
  1501. **        Input from proctab
  1502. */
  1503.  
  1504. # define BOLSTATE    0    /* beginning of line */
  1505. # define NORMSTATE    1    /* normal token */
  1506. # define EOFSTATE    2    /* end of file */
  1507. int    LineNo;            /* current line number */
  1508.  
  1509. yylex()
  1510. {
  1511.     static int state;
  1512.     static char *ptp;
  1513.     auto int ix;
  1514.     static char line[MAXLINE];
  1515.     register int c;
  1516.     register char *p;
  1517.  
  1518.     switch (state)
  1519.     {
  1520.       case EOFSTATE:
  1521.         return (0);
  1522.  
  1523.       case BOLSTATE:
  1524.         ptp = line;
  1525.         for (;;)
  1526.         {
  1527.             LineNo++;
  1528.             c = getc(ProcFile);
  1529.             if (c < 0)
  1530.             {
  1531.                 state = EOFSTATE;
  1532.                 return (0);
  1533.             }
  1534.             switch (c)
  1535.             {
  1536.               case '*':
  1537.               case '#':
  1538.               case '\n':
  1539.                 while (c != '\n' && (c = getc(ProcFile)) > 0)
  1540.                     continue;
  1541.                 break;
  1542.  
  1543.               case ':':
  1544.                 while (c != '\n' && (c = getc(ProcFile)) > 0)
  1545.                     putchar(c);
  1546.                 break;
  1547.  
  1548.               default:
  1549.                 /* regular line, return header */
  1550.                 state = NORMSTATE;
  1551.                 return (c);
  1552.             }
  1553.         }
  1554.     
  1555.       case NORMSTATE:
  1556.         yylval.yystr = ptp;
  1557.         while ((c = getc(ProcFile)) != ':' && c != '\n' && c > 0)
  1558.         {
  1559.             *ptp++ = c;
  1560.             if (c == '$')
  1561.             {
  1562.                 c = getc(ProcFile);
  1563.                 if (c < 'A' || c > 'Z')
  1564.                     *ptp++ = c;
  1565.                 else
  1566.                 {
  1567.                     ptp--;
  1568.                     for (p = Macro[c - 'A']; (*ptp++ = *p++) != '\0'; )
  1569.                         continue;
  1570.                     ptp--;
  1571.                 }
  1572.             }
  1573.         }
  1574.         
  1575.         /* compute next state */
  1576.         if (c != ':')
  1577.             state = BOLSTATE;
  1578.  
  1579.         *ptp++ = '\0';
  1580.         ix = atoi(yylval.yystr);
  1581.         if ( *yylval.yystr <= '9' && *yylval.yystr >= '0')
  1582.         {
  1583.             if (yylval.yystr[0] == '0')
  1584.                 ix = oatoi(yylval.yystr);
  1585.             yylval.yyint = ix;
  1586.             return (INT);
  1587.         }
  1588.         else
  1589.             return (STR);
  1590.     
  1591.       default:
  1592.         syserr("yylex: state %d", state);
  1593.     }
  1594. }
  1595.  
  1596.  
  1597.  
  1598.  
  1599. yyerror(s)
  1600.     char *s;
  1601. {
  1602.     syserr("Line %d: Yacc error: %s", LineNo, s);
  1603. }
  1604.  
  1605.  
  1606. /*VARARGS1*/
  1607. usrerr(f, p1, p2, p3)
  1608.     char *f;
  1609. {
  1610.     printf("Line %d: ", LineNo);
  1611.     printf(f, p1, p2, p3);
  1612.     printf("\n");
  1613. }
  1614.